package com.winner.es.exception.handler;


import com.winner.es.exception.BusinessException;
import com.winner.es.exception.EsResultEnum;
import com.winner.es.exception.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

import javax.validation.ConstraintViolationException;
import javax.validation.ValidationException;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 全局异常处理类,当抛出自定义异常后,可以给前端返回 状态码
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {

    @ExceptionHandler(value = { Exception.class })
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public Result unknownExceptionHandle(final Exception exception, final WebRequest request) {
        log.error("error code is {}, error message is {}", EsResultEnum.SYSTEM_EXCEPTION.getCode(), exception.getMessage());
        Result result = Result.error(EsResultEnum.SYSTEM_EXCEPTION);
        return result;
    }

    @ExceptionHandler(BusinessException.class)
    public Result businessException(final BusinessException exception, final WebRequest request) {
        Result error = Result.error(exception.getExceptionEnum());
        return error;
    }

    // 对多个单个字段 必填进行校验  为了捕获 ConstraintViolationException 和 ViolationException,因为是继承关系,直接捕获父类ValidationException.class
    @ExceptionHandler(value = {ValidationException.class })
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public Result constraintViolationException(final ConstraintViolationException exception) {
        Result<Object> errorResponse = Result.error(EsResultEnum.REQUEST_FIELD_ERROR);
        List<String> list = exception.getConstraintViolations().stream().map(a -> a.getMessage()).collect(Collectors.toList());
        errorResponse.setData(list);
        return errorResponse;
    }

    @Override
    protected ResponseEntity<Object> handleMethodArgumentNotValid(final MethodArgumentNotValidException exception, final HttpHeaders headers, final HttpStatus status, final WebRequest request) {
        Result<Object> errorResponse = Result.error(EsResultEnum.REQUEST_FIELD_ERROR);
        final List<ObjectError> errorsObj = exception.getBindingResult().getAllErrors();
        List<String> errors = errorsObj.stream().map(a -> a.getDefaultMessage()).collect(Collectors.toList());
        errorResponse.setData(errors);
        return handleExceptionInternal(exception, errorResponse, headers, HttpStatus.BAD_REQUEST, request);
    }

    @Override
    protected ResponseEntity<Object> handleHttpRequestMethodNotSupported(final HttpRequestMethodNotSupportedException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
        Result errorResponse = Result.error(EsResultEnum.REQUEST_METHOD_NOT_SUPPORT);
        return handleExceptionInternal(ex, errorResponse, headers, HttpStatus.BAD_REQUEST, request);
    }

    @Override
    protected ResponseEntity<Object> handleHttpMessageNotReadable(final HttpMessageNotReadableException ex, final HttpHeaders headers, final HttpStatus status, final WebRequest request) {
        Result errorResponse = Result.error(EsResultEnum.INVALIDATE_JSON_FORMAT);
        return handleExceptionInternal(ex, errorResponse, headers, HttpStatus.BAD_REQUEST, request);
    }

}
